package com.tools.genxsd.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.tools.genxsd.entity.*;
import com.tools.genxsd.entity.type.XsdAttributeType;
import com.tools.genxsd.entity.type.XsdComplexType;
import com.tools.genxsd.entity.type.XsdDecimalType;
import com.tools.genxsd.entity.type.XsdStringType;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.tools.genxsd.constant.SysConstant.UNBOUNDED;

public class XSDGenerateExt {

    //文档对象
    private Document document;

    // 根节点
    private Element root;

    public Element getRoot() {
        return root;
    }

    /**
     * 初始化XSD
     */
    public XSDGenerateExt(String xsdName) {

        document = DocumentHelper.createDocument();

        root = initRootElement(xsdName);
    }

    /**
     * 初始化头部信息
     *
     * @return
     */
    private Element initRootElement(String xsdName) {
        document.addComment("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" +
                "Legal Notices\n" +
                "\n" +
                "CIPS Co., Ltd. All Rights Reserved.\n" +
                "Generated by CIPS Standardized Platform on " + DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));

        Element root = document.addElement("xs:schema");

        root.addNamespace("", "urn:iso:std:iso:2022:tech:xsd:" + xsdName);

        root.addNamespace("xs", "http://www.w3.org/2001/XMLSchema");

        root.addAttribute("elementFormDefault", "qualified");
        root.addAttribute("targetNamespace", "urn:iso:std:iso:2022:tech:xsd:" + xsdName);

        return root;

    }

    /**
     * 添加节点
     * @param xsdElement
     */
    public void addElement(Element baseElement, XsdElement xsdElement) {

        Element newElement = baseElement.addElement("xs:element");

        String maxOccurs = xsdElement.getMaxOccurs();
        String minOccurs = xsdElement.getMinOccurs();
        if (Objects.nonNull(minOccurs)
                && Objects.nonNull(maxOccurs)
                && !Objects.equals(maxOccurs, minOccurs)) {
            newElement.addAttribute("maxOccurs", Objects.equals(maxOccurs, "n") ? UNBOUNDED : maxOccurs);
            newElement.addAttribute("minOccurs", minOccurs);
        }

        newElement.addAttribute("name", xsdElement.getName());

        XsdComplexType xsdType = xsdElement.getXsdType();
        String typeName = Objects.nonNull(xsdType) ? xsdType.getName() : xsdElement.getType();
        newElement.addAttribute("type", typeName);
    }

    /**
     * 新增复合元素
     *
     * @param xsdType 复合节点类型
     * @return
     */
    public Element addComplexType(XsdComplexType xsdType) {

        Element complexType = root.addElement("xs:complexType");

        complexType.addAttribute("name", xsdType.getName());

        return complexType.addElement(xsdType.getOrder());
    }

    public void addAttributeType(XsdAttributeType xsdType) {
        Element complexType = root.addElement("xs:complexType");

        complexType.addAttribute("name", xsdType.getName());

        Element contentElement = complexType.addElement("xs:simpleContent");
        Element extension = contentElement.addElement("xs:extension");
        extension.addAttribute("base", xsdType.getBaseType().getName());

        Element attrElement = extension.addElement("xs:attribute");
        attrElement.addAttribute("name", xsdType.getAttrName());
        attrElement.addAttribute("type", xsdType.getAttrType().getName());
        attrElement.addAttribute("use", xsdType.getUse());

        addDecimalType((XsdDecimalType) xsdType.getBaseType());
        addStringType((XsdStringType) xsdType.getAttrType());
    }

    public void addDecimalType(XsdDecimalType decimalType) {
        if (Objects.isNull(decimalType)) {
            return;
        }

        Element complexType = root.addElement("xs:simpleType");

        complexType.addAttribute("name", decimalType.getName());

        Element restriction = complexType.addElement("xs:restriction");
        restriction.addAttribute("base", decimalType.getBaseType());

        if (CharSequenceUtil.isNotBlank(decimalType.getFractionDigits())) {
            addSimpleElement(restriction, "xs:fractionDigits",
                    decimalType.getFractionDigits());
        }
        if (CharSequenceUtil.isNotBlank(decimalType.getTotalDigits())) {
            addSimpleElement(restriction, "xs:totalDigits",
                    decimalType.getTotalDigits());
        }
        if (CharSequenceUtil.isNotBlank(decimalType.getMinInclusive())) {
            addSimpleElement(restriction, "xs:minInclusive",
                    decimalType.getMinInclusive());
        }
    }

    /**
     * 新增简单元素
     *
     * @param simpleType 简单节点对象
     * @return
     */
    public void addStringType(XsdStringType simpleType) {

        if (Objects.isNull(simpleType)) {
            return;
        }

        Element complexType = root.addElement("xs:simpleType");

        complexType.addAttribute("name", simpleType.getName());

        Element restriction = complexType.addElement("xs:restriction");
        restriction.addAttribute("base", simpleType.getBaseType());

        if (CharSequenceUtil.isNotBlank(simpleType.getPattern())) {
            addSimpleElement(restriction, "xs:pattern", simpleType.getPattern());
        } else if (CollUtil.isNotEmpty(simpleType.getEnumList())) {
            List<String> enumList = simpleType.getEnumList();

            for (String enumVal : enumList) {
                addSimpleElement(restriction, "xs:enumeration", enumVal);
            }
        } else {
            if (CharSequenceUtil.isNotBlank(simpleType.getMinLength())) {
                addSimpleElement(restriction, "xs:minLength", simpleType.getMinLength());
            }

            if (CharSequenceUtil.isNotBlank(simpleType.getMaxLength())) {
                addSimpleElement(restriction, "xs:maxLength", simpleType.getMaxLength());
            }
        }
    }

    /**
     * 添加简单的节点
     * @param element
     * @param name
     * @param value
     */
    private void addSimpleElement(Element element, String name, String value) {
        Element simpleEle = element.addElement(name);
        simpleEle.addAttribute("value", value);
    }

    /***
     * 写出
     */
    public void writeToDisk(String filePath) {

        try {
            File file = new File(filePath);
            OutputFormat format = OutputFormat.createPrettyPrint();

            XMLWriter writer = new XMLWriter(new FileWriter( file), format);

            writer.write(document);

            writer.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}